﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Linq;
using System.IO;
using System.Drawing.Imaging;
#pragma warning disable CA1416 // 验证平台兼容性
namespace XW.Utils
{
    public static class ImageHelper
    {
        /// <summary>
        ///  解决图像方向问题
        /// </summary>
        /// <param name="srce">The srce.</param>
        /// <returns></returns>
        public static Image FixImageOrientation(Image srce)
        {
            const int ExifOrientationId = 0x112;
            // Read orientation tag
            if (!srce.PropertyIdList.ToList().Contains(ExifOrientationId)) return null;
            var prop = srce.GetPropertyItem(ExifOrientationId);
            var orient = BitConverter.ToInt16(prop.Value, 0);
            // Force value to 1
            prop.Value = BitConverter.GetBytes((short)1);
            srce.SetPropertyItem(prop);

            // Rotate/flip image according to <orient>
            if (orient > 1 )
            {
                srce.RotateFlip(OrientationToFlipType(orient));
            }
            else
            {
                return null;
            }
            return srce;
        }

        public static void FixImageOrientation(string filePath) {
            if (IsPicture(filePath))
            {
                using (Image img = Image.FromFile(filePath))
                {
                    var f = FixImageOrientation(img);
                    if (f != null)
                    {
                        f.Save(filePath);
                    } 
                }
                  
            }
        }
        public static bool IsPicture(string filePath)//filePath是文件的完整路径 
        {
            try
            {
                string fileClass;
                using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                {
                    BinaryReader reader = new BinaryReader(fs);

                    byte buffer;
                    byte[] b = new byte[2];
                    buffer = reader.ReadByte();
                    b[0] = buffer;
                    fileClass = buffer.ToString();
                    buffer = reader.ReadByte();
                    b[1] = buffer;
                    fileClass += buffer.ToString(); 
                    reader.Close();
                    fs.Close();
                    // 255216是jpg;7173是gif;6677是BMP,13780是PNG;7790是exe,8297是rar 
                    if (fileClass == "255216" || fileClass == "7173" || fileClass == "6677" || fileClass == "13780")   
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                } 
               
            }
            catch
            {
                return false;
            }
        }

        private static RotateFlipType OrientationToFlipType(int orientation) {

            switch (orientation)
            {
                case 1:
                    return RotateFlipType.RotateNoneFlipNone;

                case 2:
                    return RotateFlipType.RotateNoneFlipX;

                case 3:
                    return RotateFlipType.Rotate180FlipNone;
                case 4:
                    return RotateFlipType.Rotate180FlipX;
                   
                case 5:
                    return RotateFlipType.Rotate90FlipX; 
                case 6:
                    return RotateFlipType.Rotate90FlipNone;
                case 7:
                    return RotateFlipType.Rotate270FlipX;
                case 8:
                    return RotateFlipType.Rotate270FlipNone;
                default:
                    return RotateFlipType.RotateNoneFlipNone;
            }
        }


        /// <summary>
        /// 取小写文件名后缀
        /// </summary>
        /// <param name="name">文件名</param>
        /// <returns>返回小写后缀，不带“.”</returns>
        public static string GetFileExt(string name)
        {
            return name.Split(".").Last().ToLower();
        }

        /// <summary>
        /// 是否为图片文件
        /// </summary>
        /// <param name="fileExt">文件扩展名，不含“.”</param>
        public static bool IsImage(string fileExt)
        {
            List<string> al = new List<string> { "bmp", "jpeg", "jpg", "gif", "png", "ico" };
            return al.Contains(fileExt);
        }

        /// <summary>
        /// 检查是否允许文件
        /// </summary>
        /// <param name="fileExt">文件后缀</param>
        /// <param name="allowExt">允许文件数组</param>
        public static bool CheckFileExt(string fileExt, string[] allowExt)
        {
            return allowExt.Any(t => t == fileExt);
        }

        /// <summary>
        /// 无损压缩图片
        /// </summary>
        /// <param name="sFile">原图片地址</param>
        /// <param name="dFile">压缩后保存图片地址</param>
        /// <param name="flag">压缩质量（数字越小压缩率越高）1-100</param>
        /// <param name="size">压缩后图片的最大大小</param>
        /// <param name="sfsc">是否是第一次调用</param>
        /// <returns></returns>
        public static bool CompressImage(string sFile, string dFile, int flag = 90, int size = 300, bool sfsc = true)
        {
            //如果是第一次调用，原始图像的大小小于要压缩的大小，则直接复制文件，并且返回true
            FileInfo firstFileInfo = new FileInfo(sFile);
            if (sfsc == true && firstFileInfo.Length < size * 1024)
            {
                firstFileInfo.CopyTo(dFile);
                return true;
            }
            Image iSource = Image.FromFile(sFile); ImageFormat tFormat = iSource.RawFormat;
            int dHeight = iSource.Height / 2;
            int dWidth = iSource.Width / 2;
            int sW = 0, sH = 0;
            //按比例缩放
            Size tem_size = new Size(iSource.Width, iSource.Height);
            if (tem_size.Width > dHeight || tem_size.Width > dWidth)
            {
                if ((tem_size.Width * dHeight) > (tem_size.Width * dWidth))
                {
                    sW = dWidth;
                    sH = (dWidth * tem_size.Height) / tem_size.Width;
                }
                else
                {
                    sH = dHeight;
                    sW = (tem_size.Width * dHeight) / tem_size.Height;
                }
            }
            else
            {
                sW = tem_size.Width;
                sH = tem_size.Height;
            }

            Bitmap ob = new Bitmap(dWidth, dHeight);
            Graphics g = Graphics.FromImage(ob);

            g.Clear(Color.WhiteSmoke);
            g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

            g.DrawImage(iSource, new Rectangle((dWidth - sW) / 2, (dHeight - sH) / 2, sW, sH), 0, 0, iSource.Width, iSource.Height, GraphicsUnit.Pixel);

            g.Dispose();

            //以下代码为保存图片时，设置压缩质量
            EncoderParameters ep = new EncoderParameters();
            long[] qy = new long[1];
            qy[0] = flag;//设置压缩的比例1-100
            EncoderParameter eParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qy);
            ep.Param[0] = eParam;

            try
            {
                ImageCodecInfo[] arrayICI = ImageCodecInfo.GetImageEncoders();
                ImageCodecInfo jpegICIinfo = null;
                for (int x = 0; x < arrayICI.Length; x++)
                {
                    if (arrayICI[x].FormatDescription.Equals("JPEG"))
                    {
                        jpegICIinfo = arrayICI[x];
                        break;
                    }
                }
                if (jpegICIinfo != null)
                {
                    ob.Save(dFile, jpegICIinfo, ep);//dFile是压缩后的新路径
                    FileInfo fi = new FileInfo(dFile);
                    if (fi.Length > 1024 * size)
                    {
                        flag = flag - 10;
                        CompressImage(sFile, dFile, flag, size, false);
                    }
                }
                else
                {
                    ob.Save(dFile, tFormat);
                }
                return true;
            }
            catch
            {
                return false;
            }
            finally
            {
                iSource.Dispose();

                ob.Dispose();

            }
        }
        /// <summary>
        /// 制作缩略图
        /// </summary>
        /// <param name="original">图片对象</param>
        /// <param name="newFileName">新图路径</param>
        /// <param name="maxWidth">最大宽度</param>
        /// <param name="maxHeight">最大高度</param>
        public static void ThumbImg(Image original, string newFileName, int maxWidth, int maxHeight)
        {
            Size newSize = ResizeImage(original.Width, original.Height, maxWidth, maxHeight);
            using (Image displayImage = new Bitmap(original, newSize))
            {
                try {
                    //displayImage.PixelFormat
                    Compress(displayImage, newFileName, 90);
                    //displayImage.Save(newFileName, original.RawFormat); 
                }
                finally
                {
                    original.Dispose();
                }
            }
        }


        public static byte[] ThumbImg(string fileName, int maxWidth, int maxHeight)
        {
            byte[] imageBytes = File.ReadAllBytes(fileName);
            Image original = Image.FromStream(new MemoryStream(imageBytes));

            Size newSize = ResizeImage(original.Width, original.Height, maxWidth, maxHeight);
            using (Bitmap displayImage = new Bitmap(original, newSize))
            {
                try
                {
                    using (var ms = new MemoryStream()) {
                       Compress(displayImage, ms,80);
                      //displayImage.Save(ms, original.RawFormat);
                      return ms.ToArray();
                    } 
                }
                finally
                {
                    original.Dispose();
                }
            }
        }


        /// <summary>
        /// 制作缩略图
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <param name="newFileName">新图路径</param>
        /// <param name="maxWidth">最大宽度</param>
        /// <param name="maxHeight">最大高度</param>
        public static void ThumbImg(string fileName, string newFileName, int maxWidth, int maxHeight)
        {
            string ext = GetFileExt(fileName);
            if (!IsImage(ext))
            {
                return;
            }
            //CompressImage(fileName, newFileName, flag:90, 1);
            byte[] imageBytes = File.ReadAllBytes(fileName);
            Image img = Image.FromStream(new MemoryStream(imageBytes));
            ThumbImg(img, newFileName, maxWidth, maxHeight);
        }


        /// <summary>
        /// 计算新尺寸
        /// </summary>
        /// <param name="width">原始宽度</param>
        /// <param name="height">原始高度</param>
        /// <param name="maxWidth">最大新宽度</param>
        /// <param name="maxHeight">最大新高度</param>
        /// <returns></returns>
        private static Size ResizeImage(int width, int height, int maxWidth, int maxHeight)
        {
            if (maxWidth <= 0)
                maxWidth = width;
            if (maxHeight <= 0)
                maxHeight = height;
            decimal MAX_WIDTH = maxWidth;
            decimal MAX_HEIGHT = maxHeight;
            decimal ASPECT_RATIO = MAX_WIDTH / MAX_HEIGHT;

            int newWidth, newHeight;
            decimal originalWidth = width;
            decimal originalHeight = height;

            if (originalWidth > MAX_WIDTH || originalHeight > MAX_HEIGHT)
            {
                decimal factor;
                if (originalWidth / originalHeight > ASPECT_RATIO)
                {
                    factor = originalWidth / MAX_WIDTH;
                    newWidth = Convert.ToInt32(originalWidth / factor);
                    newHeight = Convert.ToInt32(originalHeight / factor);
                }
                else
                {
                    factor = originalHeight / MAX_HEIGHT;
                    newWidth = Convert.ToInt32(originalWidth / factor);
                    newHeight = Convert.ToInt32(originalHeight / factor);
                }
            }
            else
            {
                newWidth = width;
                newHeight = height;
            }
            return new Size(newWidth, newHeight);
        }


        /// <summary>
        /// 得到图片格式
        /// </summary>
        /// <param name="name">文件名称</param>
        /// <returns></returns>
        public static ImageFormat GetFormat(string name)
        {
            string ext = GetFileExt(name);
            switch (ext)
            {
                case "ico":
                    return ImageFormat.Icon;
                case "bmp":
                    return ImageFormat.Bmp;
                case "png":
                    return ImageFormat.Png;
                case "gif":
                    return ImageFormat.Gif;
                default:
                    return ImageFormat.Jpeg;
            }
        }


        private static ImageCodecInfo GetEncoderInfo(String mimeType)
        {
            int j;
            ImageCodecInfo[] encoders;
            encoders = ImageCodecInfo.GetImageEncoders();
            for (j = 0; j < encoders.Length; ++j)
            {
                if (encoders[j].MimeType == mimeType)
                    return encoders[j];
            }
            return null;
        }
        /// <summary>
        /// 图片压缩(降低质量以减小文件的大小)
        /// </summary>
        /// <param name="srcBitmap">传入的Bitmap对象</param>
        /// <param name="destStream">压缩后的Stream对象</param>
        /// <param name="level">压缩等级，0到100，0 最差质量，100 最佳</param>
        public static void Compress(Bitmap srcBitmap, Stream destStream, long level)
        {
            ImageCodecInfo myImageCodecInfo;
            System.Drawing.Imaging.Encoder myEncoder;
            EncoderParameter myEncoderParameter;
            EncoderParameters myEncoderParameters;

            // Get an ImageCodecInfo object that represents the JPEG codec.
            myImageCodecInfo = GetEncoderInfo("image/jpeg");

            // Create an Encoder object based on the GUID

            // for the Quality parameter category.
            myEncoder = System.Drawing.Imaging.Encoder.Quality;

            // Create an EncoderParameters object.
            // An EncoderParameters object has an array of EncoderParameter
            // objects. In this case, there is only one

            // EncoderParameter object in the array.
            myEncoderParameters = new EncoderParameters(1);

            // Save the bitmap as a JPEG file with 给定的 quality level
            myEncoderParameter = new EncoderParameter(myEncoder, level);
            myEncoderParameters.Param[0] = myEncoderParameter;
            srcBitmap.Save(destStream, myImageCodecInfo, myEncoderParameters);
        }
        /// <summary>
        /// 图片压缩(降低质量以减小文件的大小)
        /// </summary>
        /// <param name="srcBitMap">传入的Bitmap对象</param>
        /// <param name="destFile">压缩后的图片保存路径</param>
        /// <param name="level">压缩等级，0到100，0 最差质量，100 最佳</param>
        public static void Compress(Bitmap srcBitMap, string destFile, long level)
        {
            Stream s = new FileStream(destFile, FileMode.Create);
            Compress(srcBitMap, s, level);
            s.Close();
        }
        /// <summary>
        /// 图片压缩(降低质量以减小文件的大小)
        /// </summary>
        /// <param name="srcFile">传入的Stream对象</param>
        /// <param name="destFile">压缩后的图片保存路径</param>
        /// <param name="level">压缩等级，0到100，0 最差质量，100 最佳</param>
        public static void Compress(Stream srcStream, string destFile, long level)
        {
            Bitmap bm = new Bitmap(srcStream);
            Compress(bm, destFile, level);
            bm.Dispose();
        }
        /// <summary>
        /// 图片压缩(降低质量以减小文件的大小)
        /// </summary>
        /// <param name="srcFile">传入的Image对象</param>
        /// <param name="destFile">压缩后的图片保存路径</param>
        /// <param name="level">压缩等级，0到100，0 最差质量，100 最佳</param>
        public static void Compress(Image srcImg, string destFile, long level)
        {
            Bitmap bm = new Bitmap(srcImg);
            Compress(bm, destFile, level);
            bm.Dispose();
        }
        /// <summary>
        /// 图片压缩(降低质量以减小文件的大小)
        /// </summary>
        /// <param name="srcFile">待压缩的BMP文件名</param>
        /// <param name="destFile">压缩后的图片保存路径</param>
        /// <param name="level">压缩等级，0到100，0 最差质量，100 最佳</param>
        public static void Compress(string srcFile, string destFile, long level)
        {
            // Create a Bitmap object based on a BMP file.
            Bitmap bm = new Bitmap(srcFile);
            Compress(bm, destFile, level);
            bm.Dispose();
        }
        /// <summary>
        /// 生成OssUrl鉴权的地址
        /// </summary>
        /// <param name="filePath">/web/static/PB21-0340-0/BK_20210628104354597.jpg</param>
        /// <param name="ossCdnKey"></param>
        /// <returns>/202107301509/0842a35b08ced654c4ae92213762bec9/web/static/PB21-0340-0/BK_20210628104354597.jpg</returns>
        public static string OssTokenUrl(string filePath,string ossCdnKey)
        {
            string timestamp = DateTime.Now.ToString("yyyyMMddHHmm");
            //string timestamp = "202107301552";
            string md5hash = CryptoHelper.MD5Encrypt32(ossCdnKey + timestamp + filePath);
            filePath = "/" + timestamp + "/" + md5hash + filePath;
            return filePath;
        }
    }
}
#pragma warning restore CA1416 // 验证平台兼容性
